--
-- Author: zhouzhanglin
-- Date: 2014-10-09 17:41:07
--
local UICenterScrollView = class("UICenterScrollView",ext.Component)
UICenterScrollView.DIRECTION_VERTICAL     = 1
UICenterScrollView.DIRECTION_HORIZONTAL   = 2

function UICenterScrollView:ctor(size,direction,renderGap,centerScale)
    UICenterScrollView.super.ctor(self)

    self:setAnchorPoint(cc.p(0.5,0.5))
    self:setContentSize(size.width,size.height)
    self:setTouchEnabled(true)
    self.lockDrag = false
    self.speed=0.5
    self.direction = direction or UICenterScrollView.DIRECTION_HORIZONTAL
    self.renderGap = renderGap or 20
    self.centerScale = centerScale or 1.2 --中间对象的缩放值
    self.maxSpeed = 50
    self.touchRenderForPage = true --点击切换

    self._defaultItemIndex = 1 --显示哪个
    self._beganPos=cc.p(0,0)
    self._containerPos=cc.p(0,0)
    self._delta=cc.p(0,0)
    self._offsetX = 0
    self._offsetY = 0 
    self._touchIsDown = false
    self._clickRender = false --当前是否在点击Render状态

    self._container = display.newNode()
    self._container:setPosition(size.width/2,size.height/2)
    self._clipNode = display.newClippingRegionNode(cc.rect(0,0,size.width,size.height))
    self._clipNode:addChild(self._container)
    --设置到最左边和最上边
    if self.direction==UICenterScrollView.DIRECTION_HORIZONTAL then
        self._endX = size.width/2
        self._endY = 0
    elseif self.direction==UICenterScrollView.DIRECTION_VERTICAL then
        self._endX = 0
        self._endY = size.height/2
    end
    self:addChild(self._clipNode)

    self._enabledUpdate = true
    self:addNodeEventListener(cc.NODE_ENTER_FRAME_EVENT, handler(self, self._onEnterFrame))
    self:addNodeEventListener(cc.NODE_TOUCH_EVENT, handler(self, self._onTouchHandler))
    self:scheduleUpdate()
end

function UICenterScrollView:setClippingEnabled(value)
    self._clipNode:setClippingEnabled(value)
end

function UICenterScrollView:addItem(render)
    render:setTouchEnabled(true)
    render:setTouchSwallowEnabled(false)

    if self._renderSize == nil then
        local size = render:getCascadeBoundingBox().size
        self._renderSize = cc.size(size.width,size.height)
    end

    if self.direction==UICenterScrollView.DIRECTION_HORIZONTAL then
        local px = self._container:getChildrenCount() * (self._renderSize .width + self.renderGap)
        render:setPositionX(px)
        self._container:setContentSize(px+self._renderSize .width,self._renderSize .height)
    elseif self.direction==UICenterScrollView.DIRECTION_VERTICAL then
        local py = -self._container:getChildrenCount() * (self._renderSize .height + self.renderGap)
        render:setPositionY(py)
        self._container:setContentSize(self._renderSize .width,py+self._renderSize .height)
    end
    self._container:addChild(render)
    --设置索引值.
    render.__index = self._container:getChildrenCount()
    if render.onRealClick then
        render:onRealClick(function(event)
            local targetIndex = event.target.__index;
            if targetIndex> 0 and targetIndex~=self._defaultItemIndex then
                if self.touchRenderForPage then
                    self._clickRender = true
                    self:showIndex(targetIndex,true)
                end
            elseif self._onSelectFun~= nil then
                self._onSelectFun(self:getCenterRender())
            end
        end)
    end
end


--在addItem完成，并且添加到显示列表后调用 ,index从1开始
function UICenterScrollView:showIndex( index , animation )
    if self._defaultItemIndex==index then return end
    animation = animation or false
    self._defaultItemIndex = index
    if self._defaultItemIndex<1 then
        self._defaultItemIndex = 1
    elseif self._defaultItemIndex>self._container:getChildrenCount() then
        self._defaultItemIndex = self._container:getChildrenCount()
    end
    if self._onPageChangeFun~=nil then
        self._onPageChangeFun(self._defaultItemIndex,self._container:getChildrenCount())
    end

    if self.direction==UICenterScrollView.DIRECTION_VERTICAL then
        self._endY = (self._defaultItemIndex-1)*(self._renderSize.height+self.renderGap)+self:getContentSize().height/2
        if not animation then
            self._container:setPositionY( self._endY )
        elseif not self._enabledUpdate then
            self._enabledUpdate = true
            self:scheduleUpdate()
        end
        self:_scaleYRenders()
    else
        self._endX = -(self._defaultItemIndex-1)*(self._renderSize.width+self.renderGap)+self:getContentSize().width/2

        if not animation then
            self._container:setPositionX( self._endX )
        elseif not self._enabledUpdate then
            self._enabledUpdate = true
            self:scheduleUpdate()
        end
        self:_scaleXRenders()
    end
end

function UICenterScrollView:scrollToRender(render,animation)
    animation = animation or false
    self:showIndex(render.__index,animation)
end


function UICenterScrollView:_onEnterFrame(dt)
    if self.direction==UICenterScrollView.DIRECTION_VERTICAL then
        local speedY = (self._endY-self._container:getPositionY())*self.speed 
        if not self._touchIsDown and self._endY-self._container:getContentSize().height>-self:getContentSize().height then 
            speedY = speedY * 0.2 
        elseif not self._touchIsDown and self._endY<0 then
            speedY = speedY * 0.2 
        elseif self._clickRender then
            speedY = speedY * 0.2
        end
        if speedY>self.maxSpeed then 
            speedY=self.maxSpeed
        elseif speedY <-self.maxSpeed then 
            speedY = -self.maxSpeed
        end
        self._container:setPositionY( self._container:getPositionY()+speedY )

        self:_scaleYRenders()

        if math.abs(speedY)<0.1 then
            self._container:setPositionY( self._endY )
            if self._enabledUpdate then
                self:unscheduleUpdate()
                self._enabledUpdate = false
            end
            if self._onScrollOverFun~= nil then
                self._onScrollOverFun( self:getCenterRender())
            end
            self._clickRender = false
        end

    elseif self.direction==UICenterScrollView.DIRECTION_HORIZONTAL then

        local speedX = (self._endX-self._container:getPositionX())*self.speed 
        if not self._touchIsDown and self._endX>-self._container:getContentSize().width-self:getContentSize().width/2 then 
            speedX = speedX * 0.2
        elseif not self._touchIsDown and self._endX<self._container:getContentSize().width/2 then 
            speedX = speedX * 0.2
        elseif self._clickRender then
            speedX = speedX * 0.2
        end

        if  speedX>self.maxSpeed then 
            speedX= self.maxSpeed 
        elseif speedX <-self.maxSpeed then 
            speedX= -self.maxSpeed 
        end
        self._container:setPositionX( self._container:getPositionX()+speedX )

        --缩放
        self:_scaleXRenders()

        if math.abs(speedX)<0.1 then
            self._container:setPositionX( self._endX )
            if self._enabledUpdate then
                self:unscheduleUpdate()
                self._enabledUpdate = false
            end
            if self._onScrollOverFun~= nil then
                self._onScrollOverFun( self:getCenterRender())
            end
            self._clickRender = false
        end
    end

    --是否需要render
    for _, child in ipairs(self._container:getChildren()) do

        if  child:getPositionX()+self._container:getPositionX()+self._renderSize.width<0 or
            child:getPositionX()+self._container:getPositionX()-self._renderSize.width>self:getContentSize().width or
            child:getPositionY()+self._container:getPositionY()+self._renderSize.height<0 or
            child:getPositionY()+self._container:getPositionY()-self._renderSize.height>self:getContentSize().height
        then
            if child:isVisible() then
                child:setVisible(false)
                if child._onBecameInVisibleFun~=nil then
                    child._onBecameInVisibleFun(child)
                end
            end
        else
            if not child:isVisible() then
                child:setVisible(true)
                if child._onBecameVisibleFun~=nil then
                    child._onBecameVisibleFun(child)
                end
            end 
        end
    end

end


function UICenterScrollView:_scaleXRenders()
    if self.centerScale>1 then
        for _, render in ipairs(self._container:getChildren()) do
            local posX =  render:getPositionX()+self._container:getPositionX()-self:getContentSize().width/2
            local sc = math.sin( (self._renderSize.width*4-math.abs(posX))/self._renderSize.width/4 )*self.centerScale
            render:setScale( math.max(self.centerScale/2,sc) )
 
            if render:isVisible() then
                self._container:reorderChild(render, sc*100)
            end
 
        end
    end
end

function UICenterScrollView:_scaleYRenders()
    if self.centerScale>1 then
        for _, render in ipairs(self._container:getChildren()) do
            local posY =  render:getPositionY()+self._container:getPositionY()-self:getContentSize().height/2
            local sc = math.sin( (self._renderSize.height*4-math.abs(posY))/self._renderSize.height/4)*self.centerScale
            render:setScale( math.max(self.centerScale/2,sc) )
            if render:isVisible() then
                self._container:reorderChild(render, sc*100)
            end
        end
    end
end


function UICenterScrollView:_onTouchHandler(event)
    if self.lockDrag or self._clickRender then return end

    local name,x,y,prevX,prevY = event.name,event.x,event.y,event.prevX,event.prevY
    if name=="began" then

        self._touchIsDown = true
        self._beganPos.x = x
        self._beganPos.y = y
        self._containerPos.x = self._container:getPositionX()
        self._containerPos.y = self._container:getPositionY()
        self._endX = self._containerPos.x
        self._endY = self._containerPos.y
        self._delta.x = 0
        self._delta.y = 0
        if self._enabledUpdate then
            self:unscheduleUpdate()
            self._enabledUpdate = false
        end
        return true
    elseif name=="moved" then

        self.touchChildren = false
        self._offsetX = x-self._beganPos.x
        self._offsetY = y-self._beganPos.y

        self._endX = self._containerPos.x + self._offsetX 
        self._endY = self._containerPos.y + self._offsetY

        self._delta.x = x-prevX
        self._delta.y = y-prevY

        if not self._enabledUpdate then
            self:scheduleUpdate()
            self._enabledUpdate = true
        end
    elseif name=="ended" or name=="cancelled" then

        self._touchIsDown =false 
        self.touchChildren = true

        self._offsetX = x-self._beganPos.x
        self._offsetY = y-self._beganPos.y

        if self.direction==UICenterScrollView.DIRECTION_HORIZONTAL then

            if math.abs(self._offsetX)>10 then
                self._endX =  self._endX + self._offsetX
            else self._endX = self._container:getPositionX() end
            --遍历所有的render，判断哪个与end最接近
            local minDistance = math.huge
            local minI = 0
            
            for _, render in ipairs(self._container:getChildren()) do
                local pos =  render:getPositionX()+self._endX
                local dis = math.abs(pos-self:getContentSize().width/2)
                if dis<minDistance then
                    minDistance=dis 
                    minI = render.__index
                end
            end

            self._endX = -(minI-1)*(self._renderSize.width+self.renderGap)+self:getContentSize().width/2
            self._defaultItemIndex = minI

            if math.abs(self._endX-self._container:getPositionX())<2 then
                self._container:setPositionX(self._endX)
            else
                if not self._enabledUpdate then
                    self._enabledUpdate = true
                    self:scheduleUpdate()
                end
                if self._onPageChangeFun~=nil then
                    self._onPageChangeFun(self._defaultItemIndex,self._container:getChildrenCount())
                end
            end

        elseif self.direction==UICenterScrollView.DIRECTION_VERTICAL then

            if math.abs(self._offsetY)>10 then
                self._endY =  self._endY + self._offsetY
            else self._endY = self._container:getPositionY() end
            --遍历所有的render，判断哪个与end最接近
            local minDistance = math.huge
            local minI = 0
            
            for _, render in ipairs(self._container:getChildren()) do
                local pos =  render:getPositionY()+self._endY
                local dis = math.abs(pos-self:getContentSize().height/2)
                if dis<minDistance then
                    minDistance=dis 
                    minI = render.__index
                end
            end
            self._endY = (minI-1)*(self._renderSize.height+self.renderGap)+self:getContentSize().height/2
            self._defaultItemIndex = minI

            if math.abs(self._endY-self._container:getPositionY())<2 then
                self._container:setPositionY(self._endY)
            else
                if not self._enabledUpdate then
                    self._enabledUpdate = true
                    self:scheduleUpdate()
                end
                if self._onPageChangeFun~=nil then
                    self._onPageChangeFun(self._defaultItemIndex,self._container:getChildrenCount())
                end
            end
        end
    end

end



function UICenterScrollView:getCurrentPage()
    return self._defaultItemIndex
end
function UICenterScrollView:getTotalPage()
    return self._container:getChildrenCount()
end
function UICenterScrollView:hasNextPage()
    return self._defaultItemIndex<self._container:getChildrenCount()
end
function UICenterScrollView:hasPrevPage()
    return self._defaultItemIndex>1
end
function UICenterScrollView:prevPage()
    if self:hasPrevPage() then
        self:showIndex(self._defaultItemIndex-1,true)
    end
end
function UICenterScrollView:nextPage()
    if self:hasNextPage() then
        self:showIndex(self._defaultItemIndex+1,true)
    end
end


function UICenterScrollView:getRenders()
    return self._container:getChildren()
end
function UICenterScrollView:getCenterRender()
    for _,v in ipairs(self._container:getChildren()) do
        if v.__index ==self._defaultItemIndex then
            return v
        end
    end
    return nil
end

--fun 的回调参数为 CenterRender
function UICenterScrollView:onScrollOver( fun )
    self._onScrollOverFun = fun
    return self
end
--fun 的回调参数为 CenterRender
function UICenterScrollView:onSelect( fun )
    self._onSelectFun = fun
    return self
end
--fun的回调参数为 currentPage , totalPage
function UICenterScrollView:onPageChange( fun )
    self._onPageChangeFun = fun 
    return self
end


function UICenterScrollView:dispose()
    self:unscheduleUpdate()
    self._onPageChangeFun = nil 
    self._onScrollOverFun = nil 
    self._onSelectFun = nil
    UICenterScrollView.super.dispose(self)
end

return UICenterScrollView